package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.api.dto.trade.OrderBasicDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.domain.vo.lessonStatusVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.service.ILearningRecordService;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课表 服务实现类
 * </p>
 *
 * @author hrz
 * @since 2025-08-28
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningLessonServiceImpl
        extends ServiceImpl<LearningLessonMapper, LearningLesson>
        implements ILearningLessonService {

    final CourseClient courseClient;
    final CatalogueClient catalogueClient;

    @Autowired
    @Lazy
    ILearningRecordService learningRecordService;

    @ApiOperation("添加课程到课表")
    @Override
    public void addLesson(OrderBasicDTO order) {
        //1.查询课程相关信息
        List<CourseSimpleInfoDTO> courseSimpleInfoList =
                courseClient.getSimpleInfoList(order.getCourseIds());
        //2.封装po实体类
        ArrayList<LearningLesson> list = new ArrayList<>();
        for (CourseSimpleInfoDTO courseSimpleInfoDTO : courseSimpleInfoList) {
            LearningLesson lesson = new LearningLesson();
            lesson.setUserId(order.getUserId());
            lesson.setCourseId(courseSimpleInfoDTO.getId());
            Integer validDuration = courseSimpleInfoDTO.getValidDuration();
            if(validDuration != null){
                //当课程有过期时间时再获取到订单完成时间,加上过期间隔形成过期时间并注入
                lesson.setExpireTime(order.getFinishTime().plusDays(validDuration));
            }
            list.add(lesson);
        }
        //3.批量保存 - 使用mybatis-plus的批量保存方法
        this.saveBatch(list);
    }

    @Override
    public PageDTO<LearningLessonVO> querymyLessons(PageQuery pageQuery) {
        //1.获取当前用户id
        Long userId = UserContext.getUser();
        //2.todo 分页查询 - 使用mybatis-plus的分页查询方法获取到数据库中相应字段信息
        Page<LearningLesson> page = this.lambdaQuery()
                .eq(LearningLesson::getUserId,userId)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if(CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }
        //3.数据不为空时,将查询到的数据po转换成vo
        //先得到所有课程id
        List<Long> collect = records.stream().
                map(LearningLesson::getCourseId).
                collect(Collectors.toList());
        //再调用远程接口获取到该课程对应的名称,封面,章节数等信息
        List<CourseSimpleInfoDTO> cinfos = courseClient.getSimpleInfoList(collect);
        Map<Long, CourseSimpleInfoDTO> infos = cinfos.stream().
                collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        //4.封装vo
        List<LearningLessonVO> l = new ArrayList<>();
        for (LearningLesson record : records) {
            LearningLessonVO learningLessonVO =
                    BeanUtils.copyBean(record, LearningLessonVO.class);
            //再从map中取出相应其他信息
            CourseSimpleInfoDTO otherinfo =
                    infos.get(learningLessonVO.getCourseId());
            if(otherinfo != null){ //如果不为空就注入到vo中
                //对应名称,封面,章节数
                learningLessonVO.setCourseName(otherinfo.getName());
                learningLessonVO.setCourseCoverUrl(otherinfo.getCoverUrl());
                learningLessonVO.setSections(otherinfo.getSectionNum());
            }
            l.add(learningLessonVO);
        }
        //5.返回vo
        return PageDTO.of(page, l);
    }

    @Override
    public LearningLessonVO queryNowLesson() {
        //1.先获取当前用户id
        Long userId = UserContext.getUser();
        //2.查询当前用户最近学习的课程,按最近学习时间降序排列,且要学习中的课程
        LearningLesson course = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, 1)
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        //3.远程调用接口获取到课程的封面,章节数,名称等信息
        CourseFullInfoDTO cInfo =
                courseClient.getCourseInfoById(course.getId(), false, false);
        if(cInfo == null){
            throw new BizIllegalException("课程不存在");
        }
        //4.查询用户课表中总课程数-从课表中按用户id查询返回一个聚合函数即可
        Integer count = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .count().intValue();
        //5.查询章节信息: 小节名称,小节编号
        List<CataSimpleInfoDTO> l =
                catalogueClient.batchQueryCatalogue(CollUtils.singletonList(course.getId()));
        if(CollUtils.isEmpty(l)){
            throw new BizIllegalException("小节不存在");
        }
        //6.封装vo并返回
        LearningLessonVO vo = BeanUtils.copyBean(course, LearningLessonVO.class);
        vo.setCourseCoverUrl(cInfo.getCoverUrl());
        vo.setSections(cInfo.getSectionNum());
        vo.setCourseName(cInfo.getName());
        vo.setCourseAmount(count.intValue());
        vo.setLatestSectionIndex(l.get(0).getCIndex()); //最新学习的章节编号
        vo.setLatestSectionName(l.get(0).getName());//最新学习的章节名称
        return vo;
    }

    @Override
    public Long queryValid(Long courseId) {
        //获取当前用户id
        Long userId = UserContext.getUser();
        //根据课程id去课表中查询状态
        LearningLesson one = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId).one();
        //如果为空或者已过期,则返回null
        if(one == null || one.getStatus().equals(LessonStatus.EXPIRED)){
            return null;
        }
        //如果不为空,则返回课程id
        return one.getId();
    }

    @Override
    public lessonStatusVO queryById(Long courseId) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.根据用户id和课程id去查询课程对应状态
        LearningLesson one = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId).one();
        //3.封装VO
        return BeanUtils.copyBean(one, lessonStatusVO.class);
    }

    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        //1.根据课程id查询学习人数
        return this.lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .count().intValue();
    }

    @Override
    public void removeLesson(OrderBasicDTO order) {
        //1.获取用户id
        Long userId = order.getUserId();
        //2.获取课程id
        List<Long> courseIds = order.getCourseIds();
        //3.删除对应课程信息 - 学习记录不用删除
        this.lambdaUpdate()
                .eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getCourseId, courseIds)
                .remove();
    }

    @Override
    public void deleteCourse(Long courseId) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.根据用户id和课程id删除课程信息
        this.lambdaUpdate()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .remove();
    }

    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        //1.凭课程ID去learning_lesson表查询课表ID和最近学习的小节ID
        Long userId = UserContext.getUser(); //获取用户id
        LearningLesson one = this.lambdaQuery()
                .select(LearningLesson::getLatestSectionId,
                        LearningLesson::getId)
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId).one();
        //2.如果为空,则返回null
        if(one == null){
            return null;
        }
        //3.再去查询学习记录
        List<LearningRecord> list = learningRecordService.lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getLessonId, one.getId())
                .list();
        //封装DTO
        LearningLessonDTO lld = new LearningLessonDTO();
        lld.setId(one.getId());
        lld.setLatestSectionId(one.getLatestSectionId());
        if(CollUtils.isNotEmpty(list)){
            for (LearningRecord learningRecord : list) {
                LearningRecordDTO recordDTO = BeanUtils.copyBean(learningRecord, LearningRecordDTO.class);
                lld.getRecords().add(recordDTO);
            }
        }
        //最后将其返回即可
        return lld;
    }

    @Override
    public void addPlan(Long courseId, Integer weekFreq) {
        //根据课程ID查找到相应课表条目,将周频率更新为新的周频率
        Long userId = UserContext.getUser();
        LearningLesson lesson = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if(lesson == null){
            throw new BizIllegalException("课程不存在");
        }
        //更新数据库中的该条目的更新时间以及周频率
        lesson.setWeekFreq(weekFreq);
        lesson.setUpdateTime(LocalDateTime.now());
        this.updateById(lesson);
    }

    @Override
    public LearningPlanPageVO queryPlans(PageQuery pageQuery) {
        LearningPlanPageVO result = new LearningPlanPageVO();
        List<LearningPlanVO> voList = new ArrayList<>();
        //1.先获取用户ID
        Long userId = UserContext.getUser();
        //2.获取本周起始时间
        LocalDate now = LocalDate.now();
        LocalDateTime begin = DateUtils.getWeekBeginTime(now);
        LocalDateTime end = DateUtils.getWeekEndTime(now);
        //3.根据用户id和时间统计本周已经学习完的小节数量
        Integer NumOfSectionFinished = learningRecordService.lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .gt(LearningRecord::getFinishTime, begin)
                .lt(LearningRecord::getFinishTime, end)
                .eq(LearningRecord::getFinished, true)
                .count().intValue();
        //4.分页查询出课表信息
        Page<LearningLesson> p = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                //课程状态是未学习或者学习中都可以
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        //这其中包括了课程id,本周计划学习数量,总已学习小节数量,最近一次学习时间
        List<LearningLesson> records = p.getRecords();
        if (CollUtils.isEmpty(records)) {
            //如果没有查询出记录,则直接返回
            return result.pageInfo(null,null,null);
        }
        // 有记录的话,就统计出本周计划学习小节的总数
        int sum = records.stream().mapToInt(LearningLesson::getWeekFreq).sum();
        for (LearningLesson record : records) { //对课程进行遍历
            //课程id,本周计划学习数量,总已学习小节数量,最近一次学习时间注入VO
            LearningPlanVO VO = BeanUtils.copyBean(record, LearningPlanVO.class);
            //5.查询课程信息
            CourseFullInfoDTO courseInfoById =
                    courseClient.getCourseInfoById(record.getCourseId(),
                            false,false);
            //6.统计每个课程本周的已经学习小节数
            Integer count = learningRecordService.lambdaQuery()
                    .eq(LearningRecord::getUserId, userId)
                    .eq(LearningRecord::getLessonId, record.getId())
                    .count().intValue();
            VO.setCourseName(courseInfoById.getName()); //课程名称
            VO.setSections(courseInfoById.getSectionNum()); //课程总章节数量
            VO.setWeekLearnedSections(count); //本课程本周已学习章节数
            voList.add(VO);
        }
        //7.返回结果
        result.setWeekPoints(0);
        result.setWeekTotalPlan(sum);
        result.setWeekFinished(NumOfSectionFinished);
        return result.pageInfo(p.getTotal(), p.getPages(), voList);
    }
}